﻿//*****************************************************************************
//
//  Silver Games - Checkers
//  Copyright © 2009 Randi Relander
//      <rjrelander@users.sourceforge.net>
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation,either version 3 of the License,or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not,see <http://www.gnu.org/licenses/>.
//
//*****************************************************************************

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.Generic;
using System.Threading;

namespace Checkers.Client
{
    public partial class Board : UserControl
    {
        Tile[,] mTiles = new Tile[8, 8];

        public SynchronizationContext mGuiThread;

        public Board()
        {
            InitializeComponent();

            mGuiThread = SynchronizationContext.Current;

            mThinkTimer = new Timer(new TimerCallback(OnThinkTimer));

            InitializeTiles();
            InitializeCheckers();

            mGameModel.GetPlayer(0).ReadyToMoveEvent += new EventHandler(OnReadyToMove);
            mGameModel.GetPlayer(1).ReadyToMoveEvent += new EventHandler(OnReadyToMove);

            mGameModel.GetPlayer(0).MoveCompleteEvent += new EventHandler(OnMoveComplete);
            mGameModel.GetPlayer(1).MoveCompleteEvent += new EventHandler(OnMoveComplete);

            Reset();
        }

        public bool Paused { get; set; }

        public Checkers.Common.Game GameModel { get { return mGameModel; } }

        public void DeselectTiles()
        {
            foreach (Tile tile in mTiles)
            {
                tile.Deselect();
            }

            mSelectedTile = null;
        }

        public Tile TileModelToView(Checkers.Common.Tile tileModel)
        {
            if (tileModel == null) return null;

            int x = tileModel.X;
            int y = tileModel.Y;

            if ((x < 0) || (x >= 8)) return null;
            if ((y < 0) || (y >= 8)) return null;

            return mTiles[x, y];
        }

        Checkers.Common.Tile mSelectedTile;

        void SelectTiles()
        {
            if (mGameModel.CurrentPlayer.IsRobot)
            {
                return;
            }

            Checkers.Common.MoveList moveList = mGameModel.CurrentPlayer.MoveList;

            foreach (Checkers.Common.Move move in moveList)
            {
                TileModelToView(move.Tile1).Select2();
            }

            if (mSelectedTile != null)
            {
                TileModelToView(mSelectedTile).Select1();

                foreach (Checkers.Common.Move move in moveList)
                {
                    if (move.Tile1 == mSelectedTile)
                    {
                        TileModelToView(move.Tile2).Select2();
                    }
                }
            }
        }

        public void OnTileClicked(Tile tile)
        {
            Checkers.Common.Player player = mGameModel.CurrentPlayer;

            Checkers.Common.MoveList moveList = player.MoveList;

            Checkers.Common.Tile tile1 = mSelectedTile;

            Checkers.Common.Tile tile2 = tile.Model;

            Checkers.Common.Move move = moveList.FindMove(tile1, tile2);

            DeselectTiles();

            if (move != null)
            {
                player.ApplyMove(move);

                if (player.MoveList.Count > 0)
                {
                    mSelectedTile = tile.Model;
                }
            }
            else
            {
                if (moveList.HasStartTile(tile.Model))
                {
                    mSelectedTile = tile.Model;
                }

                SelectTiles();
            }
        }

        void OnReadyToMove(object sender, EventArgs e)
        {
            if (mGameModel.CurrentPlayer.IsRobot)
            {
                StartThinking();
            }
            else
            {
                SelectTiles();
            }
        }

        void OnMoveComplete(object sender, EventArgs e)
        {
            if (mGameModel.CurrentPlayer.MoveList.Count == 0)
            {
                mGameModel.NextPlayer();
            }
        }

        Random mRandom = new Random();

        Timer mThinkTimer;

        private void StartThinking()
        {
            mThinker.Visibility = Visibility.Visible;

            mThinkTimer.Change(500, 0);
        }

        void OnThinkTimer(object sender)
        {
            mGuiThread.Post(OnThinkTimerDone, null);
        }

        void OnThinkTimerDone(object sender)
        {
            try
            {
                mThinker.Visibility = Visibility.Collapsed;

                if (Paused) return;

                Checkers.Common.Player player = mGameModel.CurrentPlayer;

                int moves = player.MoveList.Count;

                if (moves > 0)
                {
                    Checkers.Common.Move move = player.MoveList[mRandom.Next(moves)];

                    player.ApplyMove(move);
                }
            }
            catch
            {
            }
        }

        Checkers.Common.Game mGameModel = new Checkers.Common.Game();

        private void InitializeTiles()
        {
            for (int y = 0; y < 8; y++)
            {
                StackPanel row = new StackPanel();

                row.Orientation = Orientation.Horizontal;

                mStackPanel.Children.Insert(0, row);

                for (int x = 0; x < 8; x++)
                {
                    Checkers.Common.Tile tileModel = 
                        mGameModel.Board.GetTile(x, y);

                    Tile tileView = new Tile(this, tileModel);

                    mTiles[x, y] = tileView;

                    row.Children.Add(tileView);
                }
            }
        }

        private void InitializeCheckers()
        {
            for (int playerIndex = 0; playerIndex < 2; playerIndex++)
            {
                for (int checkerIndex = 0; checkerIndex < 12; checkerIndex++)
                {
                    Checkers.Common.Checker checkerModel = 
                        mGameModel.GetChecker(playerIndex, checkerIndex);

                    Checker checkerView = new Checker(this, checkerModel);

                    mCheckerCanvas.Children.Add(checkerView);
                }
            }
        }

        public void Reset()
        {
            mThinkTimer.Change(Timeout.Infinite, Timeout.Infinite);

            Paused = false;

            DeselectTiles();

            mGameModel.Reset();
        }

        public void Pause()
        {
            Paused = true;

            mThinkTimer.Change(Timeout.Infinite, Timeout.Infinite);

            mThinker.Visibility = Visibility.Collapsed;
        }

        public void Resume()
        {
            if (Paused)
            {
                Paused = false;

                if (mGameModel.CurrentPlayer.IsRobot)
                {
                    StartThinking();
                }
            }
        }

        public void BeginGame(bool robotRed, bool robotBlack)
        {
            mGameModel.GetPlayer(0).IsRobot = robotRed;
            mGameModel.GetPlayer(1).IsRobot = robotBlack;

            Reset();

            SelectTiles();
        }
    }
}
